<template>
  <div class="project-editor">
    <div class="top">
      <div class="left">
        <el-tooltip class="box-item" effect="light" content="返回到主页" placement="bottom-start">
          <el-icon :size="20" @click="toDashboard">
            <House />
          </el-icon>
        </el-tooltip>
      </div>
      <div class="right">
        <div class="run" @click="run">
          <el-tooltip class="box-item" effect="light" content="运行" placement="bottom-start">
            <el-icon :size="25" :color="projectState != 0 ? '#48D181' : '#BDBDBD'"><CaretLeft /></el-icon>
          </el-tooltip>
        </div>
        <div class="stop" @click="stop">
          <el-tooltip class="box-item" effect="light" content="停止" placement="bottom-start">
            <el-icon :size="17" :color="projectState == 0 ? '#FF5370' : '#BDBDBD'"><WarningFilled /></el-icon>
          </el-tooltip>
        </div>
      </div>
    </div>

    <div class="bottom">
      <div class="bottom-left">
        <div class="menu">
          <file-tree :treeData="fileTreeData" :name="projectName"/>
        </div>
      </div>
      <div class="bottom-resize" title="收缩侧边栏"></div>
      <div class="bottom-right">
        <!-- right -->
        <div class="empty" v-if="!open">未打开任何文件</div>
        <code-editor @showInputVisible="handleInputVisible" ref="contentEditor" v-else/>
      </div>
    </div>

    <el-dialog width="30%" v-model="inputContentVisible" title="输入数据">
      <el-input
        placeholder="回车确认输入"
        v-model="inputContent"
        @keydown.esc="inputContentVisible = false" 
        @keydown.enter="sendInputContent" />
    </el-dialog>
  </div>
</template>

<script>
import { defineComponent, onMounted, reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import FileTree from './components/FileTree.vue'
import CodeEditor from './components/CodeEditor.vue'

import { showDirectory, getWebsocket } from "@/api/index"
import { ElMessage } from 'element-plus'

export default defineComponent({
  name: "project-editor",

  components: {
    FileTree,
    CodeEditor
  },

  setup() {
    //输入参数对话框是否显示
    const inputContentVisible = ref(false)
    const inputContent = ref('')

    let websocket = null
    
    //项目运行状态
    const projectState = ref(2)

    const router = useRouter()
    const route = useRoute()

    const open = ref(true)
    //项目名称和要展示的目录树结构
    const projectName = ref('')
    const fileTreeData = reactive([])

    //回车发送输入参数
    const sendInputContent = () => {
      console.log('参数', inputContent.value)
      //将参数内容通过websocket发送给服务器
      if (websocket != null) {
        websocket.send(JSON.stringify({
          code: 10,
          data: inputContent.value
        }))
      }
      inputContent.value = ''
      inputContentVisible.value = false
    }

    //处理子组件显示对话框的请求
    const handleInputVisible = () => inputContentVisible.value = true

    //回退
    const toDashboard = () => router.back(-1)

    //请求当前项目信息
    const getProject = () => {
      if (route.query.name == null || route.query.name.length == 0) {
        ElMessage.warning('无效的项目')
        return
      }
      showDirectory(route.query.name).then(res => {
        projectName.value = res.data.name
        fileTreeData.push(res.data)
      })
    }

    getProject()

    //得到子组件
    const contentEditor = ref()
    
    //运行当前项目/文件
    const run = () => {
      getWebsocket(route.query.pid).then(res => {
        if (res.code == 0) {
          console.log(res)
          let mainClass = contentEditor.value.getOpenFile()
          if (res.data.typeId == 1) {
            //maven项目
            mainClass = 'xxx'
            console.log('启动maven')
            start(res.data.url, mainClass)
          } else if (res.data.typeId == 2) {
            //java项目
            if (mainClass == null) {
              ElMessage.warning('请打开要启动的类')
            } else {
              //启动
              mainClass = mainClass.replaceAll('/', '&')
              mainClass = mainClass.replaceAll('\\', '&')
              start(res.data.url, mainClass)
            }
          }
        } else {
          ElMessage.error(res.msg)
          return
        }
      })
    }

    const start = (url, mainClass) => {
      //只有在非启动的状态才能运行，1、2、3分别表示启动失败、停止成功和停止失败
      if (projectState.value == 0) return
      contentEditor.value.logInfo.length = 0
      //发起长链接进行运行
      const token = sessionStorage.getItem('token')
      
      websocket = new WebSocket(`ws://localhost:8888${url}${token}/${projectName.value}/${mainClass}`)
      //连接发生错误的回调方法
      websocket.onerror = () => console.log('error')

      //连接成功建立的回调方法 
      websocket.onopen = () => console.log('连接建立成功')

      //接受到消息的回调方法
      websocket.onmessage = event => {
        //根据状态码判断需要做什么
        const data = JSON.parse(event.data)
        const code = data.code
        if (code == 0) {
          console.log('项目启动成功')
        } else if (code == 1) {
          console.log('项目启动失败')
        } else if (code == 2) {
          console.log('项目停止成功')
          websocket.close()
        } else if (code == 3) {
          console.log('项目停止失败')
          websocket.close()
        }
        console.log(data)
        if (code != 0) {
          contentEditor.value.appendLogs(data.data)
        }
        //不记录日志状态码，只记录项目运行状态
        if (code < 4 || code > 7) projectState.value = code
        console.log('项目状态码', projectState.value)
      }

      //连接关闭的回调方法
      websocket.onclose = () => {
        console.log('连接关闭')
        websocket = null
      }

      //监听窗口关闭事件， 当窗口关闭时，主动去关闭websocket链接, 防止链接还没断开就关闭窗口, server端会炮异常
      window.onbeforeunload = () => {
        websocket.close()
        websocket = null
      }
    }

    //停止当前程序
    const stop = () => {
      //只有在非停止的状态下才能停止，0表示启动成功
      if (projectState.value != 0 || websocket == null) return
      websocket.send(JSON.stringify({
        code: 11,
        data: 'stop'
      }))
    }

    //div拖拽控制
    const dragControllerDiv = () => {
      let resize = document.getElementsByClassName('bottom-resize')
      let left = document.getElementsByClassName('bottom-left')
      let right = document.getElementsByClassName('bottom-right')
      let bottom = document.getElementsByClassName('bottom')
      for (let i = 0; i < resize.length; i++) {
        //鼠标按下事件
        resize[i].onmousedown = e => {
          resize[i].style.background = '#818181'
          let startX = e.clientX
          resize[i].left = resize[i].offsetLeft
          //鼠标拖动事件
          document.onmousemove = e => {
            let endX = e.clientX
            //（endx-startx）= 移动的距离。resize[i].left+移动的距离=左边区域最后的宽度
            let moveLen = resize[i].left + (endX - startX)
            //容器宽度 - 左边区域的宽度 = 右边区域的宽度
            let maxT = bottom[i].clientWidth - resize[i].offsetWidth

            // 左边区域的最小宽度为100px
            if (moveLen < 100) moveLen = 100
            //右边区域最小宽度为700px
            if (moveLen > maxT - 700) moveLen = maxT - 700
            //设置左侧区域的宽度
            resize[i].style.left = moveLen

            for (let j = 0; j < left.length; j++) {
              left[j].style.width = moveLen + 'px'
              right[j].style.width = (bottom[i].clientWidth - moveLen - 25) + 'px'
            }
          }
          //鼠标松开事件
          document.onmouseup = e => {
            //颜色恢复
            resize[i].style.background = '#d6d6d6'
            document.onmousemove = null
            document.onmouseup = null
            //当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉
            resize[i].releaseCapture && resize[i].releaseCapture()
          }
          //该函数在属于当前线程的指定窗口里设置鼠标捕获
          resize[i].setCapture && resize[i].setCapture()
          return false
        }
      }
    }
    
    onMounted(() => dragControllerDiv())
    return {
      toDashboard,
      open,
      projectName,
      fileTreeData,
      contentEditor,
      run,
      stop,
      projectState,
      inputContentVisible,
      inputContent,
      sendInputContent,
      handleInputVisible
    }
  },
})
</script>

<style lang="scss">
.project-editor {

  .el-dialog {
    border-radius: 10px;
  }

  .top {
    height: 50px;
    display: flex;
    justify-content: space-between;
    border: 1px solid #DCDCDC;
    background-color: #F5F5F5;

    .left {
      height: 50px;
      line-height: 50px;
      margin-left: 20px;

      .el-icon:hover {
        background-color: #E6E6E8;
      }
    }
    
    .right {
      display: flex;
      margin-top: 10px;

      .run, .stop {
        width: 25px;
        height: 25px;
        text-align: center;
        cursor: pointer;
        border-radius: 5px;
      }

      .run:hover, .stop:hover {
        background-color: #E5E5E7;
      }

      .stop {
        margin-top: 3px;
        margin-right: 100px;
        margin-left: 10px;
        cursor: pointer;
      }
    }
  }

  .bottom {
    width: 100%;
    height: 700px;
    margin: 0px;
    overflow: hidden;
    box-shadow: -1px 9px 10px 3px rgba(0, 0, 0, 0.11);

    /*左侧div样式*/
    .bottom-left {
      width: calc(16% - 10px);  /*左侧初始化宽度*/   
      height: 100%;
      float: left;
      background-color: #F5F5F5;
      color: #202A3D;
      border: 1px solid #DCDCDC;
      border-width: 0 1px 1px 0;
    }

    /*拖拽区div样式*/
    .bottom-resize {
      cursor: col-resize;
      float: left;
      position: relative;
      background-color: #d6d6d6;
      border-radius: 5px;
      width: 5px;
      height: 700px;
      background-size: cover;
      background-position: center;
      color: white;
    }

    /*拖拽区鼠标悬停样式*/
    .bottom-resize:hover {
      color: #444444;
    }

    /*右侧div样式*/
    .bottom-right {
      float: left;
      height: 100%;
      width: 83%;
      background-color: #FEFEFE;
      // background-color: red;
      border: 1px solid #DCDCDC;
      border-width: 0 1px 1px 1px;

      .empty {
        color: #202A3D;
        font-size: 16px;
        text-align: center;
        width: 100%;
        height: 100%;
        line-height: 88vh;
      }
    }
  }
}
</style>
